﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Office.Interop.Excel;
using Microsoft.Win32;
using VitCode.Castle.Entities;
using VitCode.ObjectResolutionHelper;

namespace VitCode.ObjectSettingApp
{
    public class ImportSettingHelper : BaseHelper
    {
        public ImportSettingHelper(string assName)
        {
            m_AssName = assName;
            InitInfo();
        }

        public ArrayList AssTypes { get; set; }

        public string GetClassContext(Type objType)
        {
            return GetClassContext(objType, m_AssName);
        }

        StringBuilder sbUniqueInnerXml;
        StringBuilder sbExistsInnerXml;
        StringBuilder sbColumnsInnerXml;

        private NameValueCollection m_ExcelTitleInfos;
 
        public void AppExcelColumnInfo(string title,string appVal)
        {
            var val = m_ExcelTitleInfos.Get(title);
            if(!String.IsNullOrEmpty(val))
            {
                val += "\r\n"+appVal;
                m_ExcelTitleInfos[title]= val;
            }
        }

        public void SetColumnInfo(string strName,string strMemo,int minLen,int maxLen)
        {
            sbColumnsInnerXml.Append("\t\t\t<item " + ImportKeyInfo.NAME + "=\"" + strName
                + "\" " + ImportKeyInfo.MEMO + "=\"" + strMemo + "\" " + ImportKeyInfo.MIN_LENGTH + "=\"" + minLen + "\" " + ImportKeyInfo.MAX_LENGTH + "=\"" + maxLen + "\"></item>\r\n");
            var strVal = "";
            if(minLen==0)
                strVal = "选填\r\n内容长度不能超过" + maxLen + "个字符";
            else
                strVal = "必填\r\n内容长度不能超过" + maxLen + "个字符";
            m_ExcelTitleInfos.Add(strMemo,strVal);
        }

        

        public void InitInnerXml(Type objType)
        {
            sbColumnsInnerXml = new StringBuilder();
            sbExistsInnerXml = new StringBuilder();
            sbUniqueInnerXml = new StringBuilder();
            m_ExcelTitleInfos = new NameValueCollection();

            PropertyInfo[] pros = LookUpClassHelper.GetPros(objType);
            var scNotCreateProNames = GetSysProNames(objType);
            var scObjKeyProNames = GetKeyProNames(objType);
            var keyProNames = LookUpClassHelper.ConvertStringValue(scObjKeyProNames);
            sbUniqueInnerXml.Append("\t\t\t\t<item Class=\"" + objType.Name + "\" ProNames=\"" + keyProNames + "\"></item>\r\n");
            foreach (PropertyInfo p in pros)
            {
                if (p.Name == ID || scNotCreateProNames.Contains(p.Name))
                    continue;
                string dbTypeName = m_DbTypeMapping.Get(p.PropertyType.ToString());
                var minLen = 0;
                if (m_UniquePros.Contains(p.Name))
                    minLen = 1;
                if(string.IsNullOrEmpty(dbTypeName))
                {
                    var scChildKeyProNames = GetKeyProNames(p.PropertyType);
                    var childClassMemo = LookUpClassHelper.GetOrMemoDesValue(p.PropertyType);
                    var sb = new StringBuilder();
                    for(var i=0;i < scChildKeyProNames.Count;i++)
                    {
                        var keyProName = scChildKeyProNames[i];
                        var keyProInfo = p.PropertyType.GetProperty(keyProName);
                        if (keyProInfo == null)
                            throw new ArgumentException("Class["+p.PropertyType.Name+"]找不到Property["+keyProName+"]");
                        var keyProMemo = LookUpClassHelper.GetOrMemoDesValue(keyProInfo);
                        var maxLen = GetProMaxLength(p.PropertyType, keyProName);
                        var strName = p.Name + "." + keyProName;
                        var strMemo = "所属" + childClassMemo + keyProMemo;
                        if (sb.Length > 0) sb.Append(",");
                        sb.Append(strName);
                        SetColumnInfo(strName, strMemo, minLen, maxLen);
                        AppExcelColumnInfo(strMemo, strMemo + "必存在系统中存在");
                    }
                    sbExistsInnerXml.Append("\t\t\t\t<item Class=\"" + p.PropertyType.Name + "\" ProNames=\"" + sb + "\"></item>\r\n");
                }
                else
                {
                    var proInfo = objType.GetProperty(p.Name);
                    var objMemo = LookUpClassHelper.GetOrMemoDesValue(objType);
                    if (proInfo == null)
                        throw new ArgumentException("Class[" + objType.Name + "]找不到Property[" + p.Name + "]");
                    var proMemo = LookUpClassHelper.GetOrMemoDesValue(proInfo);
                    if (scObjKeyProNames.Contains(p.Name))
                        minLen = 1;
                    var maxLen = GetProMaxLength(p);
                    SetColumnInfo(p.Name, proMemo, minLen, maxLen);
                    if(scObjKeyProNames.Contains(p.Name) )
                    {
                        AppExcelColumnInfo(proMemo,
                                           "当操作为\"导入\"时,此" + objMemo + proMemo + "不能在系统中存在;\r\n当操作为\"更新\"时,此" + objMemo +
                                           proMemo + "必须在系统中存在;");
                    }
                    else if (m_UniquePros.Contains(p.Name))
                    {
                        sbUniqueInnerXml.Append("\t\t\t\t<item Class=\"" + objType.Name + "\" ProNames=\"" + p.Name + "\"></item>\r\n");
                        AppExcelColumnInfo(proMemo,
                                           "当操作为\"导入\"时,此" + objMemo + proMemo + "不能在系统中存在;\r\n当操作为\"更新\"时,此" + objMemo +
                                           proMemo + "必须在系统中存在;");
                    }
                }
            }
        }

        protected object oMissing = Missing.Value;

        public void OutputExcelFile(string filePath)
        {
            if (m_ExcelTitleInfos == null || m_ExcelTitleInfos.Count == 0)
                return;
            var xlApp = new ApplicationClass();
            Workbook wb = xlApp.Workbooks.Add(oMissing);
            try
            {
                Range rg = null;
                Worksheet ws = ((Worksheet)wb.Worksheets[1]);
                
                ws.Cells.NumberFormatLocal = "@";
                for(var i=0;i<m_ExcelTitleInfos.Count;i++)
                {
                    rg = (Range)ws.Cells[1, i+1];
                    rg.Value2 = m_ExcelTitleInfos.GetKey(i);
                    rg.Font.Bold = true;
                    var strComment = m_ExcelTitleInfos.Get(i);
                    if (strComment.StartsWith("必填"))
                        rg.Font.ColorIndex = 3;
                    rg.AddComment(strComment);
                    rg.Comment.Shape.TextFrame.AutoSize = true;
                }
                var temp = "A1";
                Validation rgVal = (ws.get_Range(ws.Cells[2,m_ExcelTitleInfos.Count+1],ws.Cells[ws.Rows.Count,m_ExcelTitleInfos.Count+1])).Validation;
                rgVal.Delete();
                rgVal.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop,XlFormatConditionOperator.xlBetween, "导入,更新", oMissing);
                rgVal.IgnoreBlank = true; rgVal.InCellDropdown = true;
                rgVal.IMEMode = Convert.ToInt32(XlIMEMode.xlIMEModeNoControl); rgVal.ShowInput = true; rgVal.ShowError = true;

                rg = ((Range) ws.Cells[1, m_ExcelTitleInfos.Count+1]);
                rg.Validation.Delete();
                rg.Value2 = "操作";
                rg.AddComment("必选");
                rg.Font.Bold = true;
                rg.Font.ColorIndex = 3;


                rg = ws.get_Range(ws.Cells[1, 1], ws.Cells[ws.Rows.Count, m_ExcelTitleInfos.Count + 1]);
                var o = rg.EntireColumn.AutoFit();

                SaveExcel(filePath, wb);
            }
            catch(Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (wb != null)
                    wb.Close(oMissing, oMissing, oMissing);
                xlApp.Quit();
                Marshal.ReleaseComObject(wb);
                Marshal.ReleaseComObject(xlApp);
                wb = null;
                xlApp = null;
                GC.Collect();
            }
        }

        public Int32 ExistsRegedit()
        {
            int ifused = -1;
            RegistryKey rk = Registry.LocalMachine;
            RegistryKey akey = rk.OpenSubKey(@"SOFTWARE\\Microsoft\\Office\\11.0\\Word\\InstallRoot\\");
            RegistryKey akeytwo = rk.OpenSubKey(@"SOFTWARE\\Microsoft\\Office\\12.0\\Word\\InstallRoot\\");
            //檢查本機是否安裝Office2003
            if (akey != null)
            {
                string file03 = akey.GetValue("Path").ToString();
                if (File.Exists(file03 + "Excel.exe"))
                {
                    ifused = 1;
                }
            }
            //檢查本機是否安裝Office2007
            if (akeytwo != null)
            {
                string file07 = akeytwo.GetValue("Path").ToString();
                if (File.Exists(file07 + "Excel.exe"))
                {
                    ifused = 2;
                }
            }
            return ifused;
        }

        public bool SaveExcel(string filePath, Workbook wb)
        {
            if (File.Exists(filePath)) File.Delete(filePath);
            bool isResult = false;
            int ifused = ExistsRegedit();
            switch (ifused)
            {
                case 2:
                    wb.SaveAs(filePath, XlFileFormat.xlExcel8, Type.Missing,
                          Type.Missing, Type.Missing, Type.Missing,
                          XlSaveAsAccessMode.xlNoChange, Type.Missing,
                          Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                    isResult = true;
                    break;
                case 1:
                    wb.SaveAs(filePath, oMissing, oMissing, oMissing, oMissing, oMissing, XlSaveAsAccessMode.xlExclusive, oMissing,
                               oMissing, oMissing, oMissing, oMissing);
                    isResult = true;
                    break;
                default:
                    wb.SaveAs(filePath, XlFileFormat.xlExcel8, Type.Missing,
                        Type.Missing, Type.Missing, Type.Missing,
                        XlSaveAsAccessMode.xlNoChange, Type.Missing,
                        Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                    isResult = true;
                    break;
            }
            return isResult;
        }

        public string GetClassContext(Type objType, string assName)
        {
            m_Checker.CheckClass(objType);
            string strDes = LookUpClassHelper.GetOrMemoDesValue(objType);
            
            var sb = new StringBuilder();
            PropertyInfo pId = objType.GetProperty("Id");
            if (pId == null)
                throw new Exception("对象解析框架要求对象必需包含Id属性");

            sb.Append("\t<" + objType.Name + " KeyProperty=\"Id\" AssemblyName=\"" + m_AssName + "\" NameSpace=\"" +
                      objType.Namespace + "\" Memo=\"" + strDes + "\">\r\n");

            InitInnerXml(objType);

            sb.Append("\t\t<"+ImportKeyInfo.COLUMNS+">\r\n");
            sb.Append(sbColumnsInnerXml);
            sb.Append("\t\t</"+ImportKeyInfo.COLUMNS+">\r\n");
            sb.Append("\t\t<" + ImportKeyInfo.CHECKS + ">\r\n");
            sb.Append("\t\t\t<" + ImportKeyInfo.UNIQUE + ">\r\n");
            sb.Append(sbUniqueInnerXml);
            sb.Append("\t\t\t</" + ImportKeyInfo.UNIQUE + ">\r\n");
            sb.Append("\t\t\t<" + ImportKeyInfo.EXISTS + ">\r\n");
            sb.Append(sbExistsInnerXml);
            sb.Append("\t\t\t</" + ImportKeyInfo.EXISTS + ">\r\n");
            sb.Append("\t\t</" + ImportKeyInfo.CHECKS + ">\r\n"); 

            sb.Append("\t</" + objType.Name + ">");

            string dirPath = AppDomain.CurrentDomain.BaseDirectory + "Settings\\ImportFiles";
            //string dirPath = "c:";
            if(!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            var excelFilePath = dirPath+"\\"+LookUpClassHelper.GetOrMemoDesValue(objType)+"导入模板.xls";
            OutputExcelFile(excelFilePath);
            return sb.ToString();
        }

       
        
    }
}
